home *** CD-ROM | disk | FTP | other *** search
/ The Learning Curve / The Learning Curve (Weird Science, 1996).iso / geography / drawmap / pop-drawmap.c < prev    next >
C/C++ Source or Header  |  1989-09-24  |  24KB  |  726 lines

  1. /*
  2.  *  The functions for pop-up menus
  3.  *
  4.  *  Written by Derek Zahn (Gambit Software, Madison WI), July 1987
  5.  *
  6.  *  This code is freely distributable and is blessed by its author for
  7.  *  inclusion, in this form or any other, into Amiga programs,
  8.  *  commercial or non-commercial.  If this is done, no credit must be
  9.  *  given to me (although I wouldn't mind).
  10.  *
  11.  *  This code was developed and tested under Manx Aztec C, version 3.40a
  12.  *  with small code, small data, and short integers as part of the Gambit
  13.  *  Software development environment.  It has been "unGambitized" for
  14.  *  general use.  I am unfamiliar with other Amiga C compilers, so cannot
  15.  *  speculate on any porting difficulties.  This file was created with a
  16.  *  text editor (Z) whose tabstops were set to 8, so that it may be easily
  17.  *  and intelligibly printed.  This code was developed under 1.2; I am
  18.  *  not sure if it will work under 1.1, but can't see why not.
  19.  *
  20.  *  Note that there are some features that should be supported but are not,
  21.  *  and some issues about the function and interface that make me nervous.
  22.  *  These are explained in the appendix to the documentation.  I would
  23.  *  greatly appreciate receiving any enhancements and modifications to this
  24.  *  code, or suggestions therefor.  Comments on techniques and coding
  25.  *  style are always appreciated.  Enjoy.
  26.  */
  27.  
  28. /* include files */
  29.  
  30. #include <exec/types.h>
  31. #include <intuition/intuitionbase.h>
  32. #include <intuition/intuition.h>
  33. #include <graphics/gfxmacros.h>
  34. #include "popmenu.h"
  35. #include "exec/memory.h"
  36.  
  37. /* Externally defined functions used in this module */
  38.  
  39. extern struct Window *OpenWindow();
  40. extern struct IntuiMessage *GetMsg();  /* type coercion, true... */
  41.  
  42. extern VOID CloseWindow(), ReplyMsg(), Wait();
  43. extern VOID RectFill(), Move(), Draw(), Text(), PrintIText(), DrawImage();
  44.  
  45. /* The following functions are defined in this module */
  46.  
  47. extern LONG PopChoose();               /* blocking user interface */
  48.                                        /*   -- exported           */
  49. extern SHORT pop_computestate();       /* see who is selected, */
  50.                                        /*   if anybody         */
  51. extern VOID pop_highlight();           /* highlight the specified item */
  52. extern VOID pop_unhighlight();         /* unhighlight the specified item */
  53. extern VOID pop_do_highlighting();     /* high or un high light the item */
  54. extern VOID pop_render();              /* draws the title (if existent) */
  55.                                        /*   and menu items              */
  56. extern VOID pop_draw_menuitem();       /* draws the menu item */
  57. extern struct MenuItem *pop_getitem(); /* find a MenuItem struc */
  58. extern SHORT pop_strlen();             /* local strlen() */
  59.  
  60. /* This is structure will be used to create a window for display of the    */
  61. /* menu.  In my heart of hearts, I wanted to use graphics library          */
  62. /* functions instead, but reason prevailed.  Note the use of the RMBTRAP   */
  63. /* flag -- while the pop-up menu is being processed, there is no use for   */
  64. /* the right button.  Perhaps this should only be set if the right button  */
  65. /* has some bearing on the pop-up menu.                                    */
  66.  
  67. static struct NewWindow pop_window =  {
  68.    0, 0,                               /* LeftEdge, TopEdge: will be */
  69.                                        /*   filled in later          */
  70.    0, 0,                               /* Width, Height: will be */
  71.                                        /*   filled in later      */
  72.    (UBYTE) -1, (UBYTE) -1,             /* BlockPen, DetailPen */
  73.    MOUSEBUTTONS | MOUSEMOVE,           /* IDCMP flags */
  74.    SMART_REFRESH | REPORTMOUSE | ACTIVATE | RMBTRAP, /* flags */
  75.    NULL,                               /* no gadgets */
  76.    NULL,                               /* checkmark inherited later */
  77.    NULL,                               /* no title */
  78.    NULL,                               /* Screen -- will be filled in later */
  79.    NULL,                               /* No custom bitmap */
  80.    0, 0,                               /* MinWidth, MinHeight -- no change */
  81.                                        /*   in size necessary              */
  82.    0, 0,                               /* MaxWidth, MaxHeight -- no change */
  83.                                        /*   in size necessary              */
  84.    CUSTOMSCREEN                        /* always use this value */
  85. };
  86.  
  87. /* It is assumed that the following point to bases of opened libraries     */
  88.  
  89. extern struct IntuitionBase *IntuitionBase;
  90. extern struct GfxBase *GfxBase;
  91.  
  92. /* ============================================================= */
  93.  
  94. /*
  95.  * PopChoose (menu, win)
  96.  * menu -- pointer to the menu to pop
  97.  * win -- the window to which this menu relates.  NULL means the currently
  98.  * active window.
  99.  *
  100.  * This function provides a blocking pop-up menu.  It returns (LONG) -1 if 
  101.  * either an error occurred attempting to pop or if no selection was made
  102.  * by the user.  If a selection was made, a LONG between 0 and n-1, where
  103.  * n is the number of Menu Items.
  104.  *
  105.  * -1 is also returned if a selection of a checked item was made.
  106.  *
  107.  * Since this code opens a window, it is up to the caller to be sure that
  108.  * no scribbling in droll ways is done while this code is in progress.
  109.  */
  110.  
  111. LONG PopChoose (menu, win)
  112.  
  113. struct Menu *menu;
  114. struct Window *win;
  115.  
  116. {
  117.  
  118.    extern UWORD *arrow;                /* pointer to data for mouse */
  119.    extern int arrow_x_offset, arrow_y_offset, arrow_size;
  120.    
  121.    struct Screen *screen;              /* the window's screen */
  122.    struct Window *popwin;              /* the pop-up menu */
  123.    struct IntuiMessage *message;       /* our eyes and ears */
  124.    struct MenuItem *sel_item;          /* the selected item */
  125.    SHORT pop_state, pop_newstate;      /* menu selection state varaibles */
  126.    SHORT mouse_moved;                  /* keeps track of whether the */
  127.                                        /*   mouse has moved          */
  128.    SHORT finished;                     /* set when menu should be blown away */
  129.    SHORT class;                        /* incoming IntuiMessage class */
  130.    SHORT code;                         /* incoming IntuiMessage code */
  131.    ULONG exclude;                      /* for handling mutual exclusion */
  132.  
  133.    /* Check to see that IntuitionBase and GfxBase are non-null.       */
  134.    /* While this is not any sort of guarantee against disaster, it    */
  135.    /* is better than nothing.                                         */
  136.  
  137.    if ((IntuitionBase == NULL) || (GfxBase == NULL))
  138.       return ((LONG) (-1));
  139.  
  140.    /* One paranoid check */
  141.  
  142.    if (menu == NULL)
  143.       return ((LONG) (-1));
  144.  
  145.    /* If the menu is not MENUENABLED, nothing to do                   */
  146.  
  147.    if (!(menu->Flags & MENUENABLED))
  148.       return ((LONG) (-1));
  149.  
  150.    /* Form the menu window to blast forth into the Visual World. Note */
  151.    /* the unconventional (and inconsistent with Intuition) ways that  */
  152.    /* the Width and Height fields are used here.                      */
  153.  
  154.    pop_window.Width = menu->Width;
  155.    pop_window.Height = menu->Height;
  156.  
  157.    if (win == NULL)
  158.       win = IntuitionBase->ActiveWindow;
  159.    if (win == NULL)                     /* panic */
  160.       return ((LONG) (-1));
  161.  
  162.    /* Inherit CheckMark from the "parent" window                      */
  163.  
  164.    if (win->CheckMark)
  165.       pop_window.CheckMark = win->CheckMark;
  166.  
  167.    screen = win->WScreen;
  168.    pop_window.Screen = screen;
  169.  
  170.    pop_window.LeftEdge = menu->LeftEdge;
  171.    pop_window.TopEdge = menu->TopEdge;
  172.  
  173.    /* if we are supposed to return to the last-selected menu item and */
  174.    /* such a beast exists, all other positioning information (except  */
  175.    /* POPTIDY) will be circumvented.  The menu will appear under the  */
  176.    /* pointer with the last-chosen item pre-selected, if this is      */
  177.    /* possible given the POPTIDY flag and the screen constraints.     */
  178.    /* In this case, the LeftEdge and TopEdge fields of the menu       */
  179.    /* structure will have been altered (I know, ick!) to provide a    */
  180.    /* relative offset with respect to the pointer to do the deed      */
  181.  
  182.    if ((menu->Flags & POPREMEMBER) && (menu->Flags & POPUSED))  {
  183.       pop_window.LeftEdge += screen->MouseX;
  184.       pop_window.TopEdge += screen->MouseY;
  185.    }
  186.    else  {
  187.       if (menu->Flags & POPPOINTREL)  {
  188.          pop_window.LeftEdge += screen->MouseX;
  189.          pop_window.TopEdge += screen->MouseY;
  190.       }
  191.       else if (menu->Flags & POPWINREL)  {
  192.          pop_window.LeftEdge += win->LeftEdge;
  193.          pop_window.TopEdge += win->TopEdge;
  194.       }
  195.    }
  196.  
  197.    /* If the caller wishes us to be POPTIDY, the menu must completely */
  198.    /* appear on the screen, whatever other effects this may have on   */
  199.    /* menu positioning.  The left edge and top edge must be altered   */
  200.    /* accordingly.  In the pathological case where the menu is larger */
  201.    /* than the screen, -1 is returned.                                */
  202.    /* If poptidiness is not a factor, the size of the window may have */
  203.    /* to be altered if it shoots off the bottom or right edge of the  */
  204.    /* screen.  There should be some similar mechanism to deal with    */
  205.    /* the menu if it extends past the top or left edge of the screen; */
  206.    /* as it stands now, the OpenWindow() call will fail, and the      */
  207.    /* result may be even more dire under 1.1.  Use 1.2!               */
  208.  
  209.    if (menu->Flags & POPTIDY)  {
  210.       if ((pop_window.Width > screen->Width) || 
  211.          (pop_window.Height > screen->Height))
  212.             return ((LONG) (-1));
  213.       if (pop_window.LeftEdge + pop_window.Width > screen->Width)
  214.          pop_window.LeftEdge = screen->Width-pop_window.Width;
  215.       if (pop_window.TopEdge + pop_window.Height > screen->Height)
  216.          pop_window.TopEdge=screen->Height-pop_window.Height;
  217.       if (pop_window.LeftEdge < screen->LeftEdge)
  218.          pop_window.LeftEdge = screen->LeftEdge;
  219.       if (pop_window.TopEdge < screen->TopEdge)
  220.          pop_window.TopEdge = screen->TopEdge;
  221.    }
  222.    else  {
  223.       if (pop_window.LeftEdge + pop_window.Width > screen->Width)
  224.          pop_window.Width = screen->Width - pop_window.LeftEdge;
  225.       if (pop_window.TopEdge + pop_window.Height > screen->Height)
  226.          pop_window.Height = screen->Height - pop_window.TopEdge;
  227.    }
  228.  
  229.    /* There!  Finally, the window is ready to be displayed!  First,   */
  230.    /* create it.                                                      */
  231.  
  232.    popwin = OpenWindow (&pop_window);
  233.    if (popwin == NULL)                 /* all that work for nuthin' */
  234.       return ((LONG) (-1));
  235.    
  236.    SetPointer (popwin, arrow, arrow_size/4-2, 16,
  237.                arrow_x_offset, arrow_y_offset);
  238.  
  239.    /* Now, render the menu items and (possibly) the menu title.       */
  240.  
  241.    pop_render (popwin, menu);
  242.  
  243.    /* Now, see if the pointer is over a selection.  The variable      */
  244.    /* 'pop_state' will from this point on hold the value, in linear   */
  245.    /* traversal order of the MenuItems (zero-indexed), the currently  */
  246.    /* selected menu item, or -1 if none are selected.                 */
  247.  
  248.    pop_state = pop_computestate (popwin, menu);
  249.  
  250.    /* If one is indeed currently selected, highlight it.              */
  251.  
  252.    if (pop_state >= 0)
  253.       pop_highlight (popwin, menu, pop_state);
  254.  
  255.    /* Here is the IDCMP loop that will process the pop-up menu.  Note */
  256.    /* that on mousemove events, I don't care where it moved, just if  */
  257.    /* it did -- pop_computestate() will figure out where by reaching  */
  258.    /* into the Window structure.  Not Pure Programming, somehow, but  */
  259.    /* blessed by the Intuition manual.                                */
  260.  
  261.    finished = 0;
  262.    while (1)  {
  263.       mouse_moved = 0;
  264.       Wait ((ULONG) 1L << popwin->UserPort->mp_SigBit);
  265.       while (message = GetMsg (popwin->UserPort))  {
  266.          class = message->Class;
  267.          code = message->Code;
  268.          ReplyMsg (message);
  269.  
  270.          /* The only messages we should be getting are      */
  271.          /* mouse button and move events.  Button events    */
  272.          /* could signify the end of this routine's         */
  273.          /* epheremal spotlight role.                       */
  274.  
  275.          switch (class)  {
  276.          case MOUSEMOVE:
  277.             mouse_moved = 1;
  278.             break;
  279.          case MOUSEBUTTONS:
  280.             switch (code)  {
  281.             case SELECTDOWN:
  282.                if ((menu->Flags & POPLEFTBUTTON) &&
  283.                 (menu->Flags & POPTRIGGERDOWN))
  284.                    finished = 1;
  285.                break;
  286.             case SELECTUP:
  287.                if ((menu->Flags & POPLEFTBUTTON) &&
  288.                 (menu->Flags & POPTRIGGERUP))
  289.                    finished = 1;
  290.                break;
  291.             case MENUDOWN:
  292.                if ((menu->Flags & POPRIGHTBUTTON) &&
  293.                 (menu->Flags & POPTRIGGERDOWN))
  294.                    finished = 1;
  295.                break;
  296.             case MENUUP:
  297.                if ((menu->Flags & POPRIGHTBUTTON) &&
  298.                 (menu->Flags & POPTRIGGERUP))
  299.                    finished = 1;
  300.                break;
  301.             default:                   /* huh? */
  302.                break;
  303.             }
  304.             break;
  305.          default:                      /* huh? */
  306.             break;
  307.          }
  308.       }
  309.  
  310.       /* if the exit conditions have been met, we can return our */
  311.       /* results with honor and dignity, having served.          */
  312.       /* Note that if we are remembering the last selection, the */
  313.       /* menu structure is mangled to make that possible.        */
  314.  
  315.       if (finished)  {
  316.          pop_state = pop_computestate (popwin, menu);
  317.          if (pop_state >= 0)  {
  318.             if (menu->Flags & POPREMEMBER)  {
  319.                menu->Flags |= POPUSED;
  320.                menu->LeftEdge = -1 * popwin->MouseX;
  321.                menu->TopEdge =  -1 * popwin->MouseY;
  322.             }
  323.  
  324.             /* Special things to do if the menu entry  */
  325.             /* is of type CHECKIT                      */
  326.  
  327.             sel_item = pop_getitem (menu, pop_state);
  328.             if (sel_item->Flags & CHECKIT)  {
  329.                if (sel_item->Flags & CHECKED)  {
  330.                   pop_state = -1;
  331.                   if (sel_item->Flags & MENUTOGGLE)
  332.                      sel_item->Flags &= ~CHECKED;
  333.                }
  334.                else  {
  335.                   sel_item->Flags |= CHECKED;
  336.  
  337.                   /* Handle mutual exclusion */
  338.  
  339.                   exclude = sel_item->MutualExclude;
  340.                   if (exclude)  {
  341.                      sel_item = menu->FirstItem;
  342.                      while (sel_item)  {
  343.                         if (exclude & 1)
  344.                            sel_item->Flags &= ~CHECKED;
  345.                         exclude >>= 1;
  346.                         sel_item = sel_item->NextItem;
  347.                      }
  348.                   }
  349.                }
  350.             }
  351.          }
  352.          ClearPointer (popwin);
  353.          CloseWindow (popwin);
  354.          return ((LONG) pop_state);
  355.       }
  356.  
  357.       /* if the mouse has moved, find out its new state and      */
  358.       /* alter the highlighting accordingly.                     */
  359.  
  360.       if (mouse_moved)  {
  361.          pop_newstate = pop_computestate (popwin, menu);
  362.          if (pop_newstate != pop_state)  {
  363.             if (pop_state >= 0)
  364.                pop_unhighlight (popwin, menu, pop_state);
  365.             if (pop_newstate >= 0)
  366.                pop_highlight (popwin, menu, pop_newstate);
  367.             pop_state = pop_newstate;
  368.          }
  369.       }
  370.    }
  371. }
  372.  
  373. /* ============================================================= */
  374.  
  375. /*
  376.  * pop_computestate()
  377.  *
  378.  * This function checks to see where the mouse pointer is in relation to
  379.  * the various menu items in the menu.  If it is inside one of them, it
  380.  * returns which one (indexed by its linear position in the MenuItem list
  381.  * with 0 being the first one).  If not, returns -1.
  382.  *
  383.  * Possible future enhancement: keep a set of state variables containing
  384.  * the UL and LR corners of the last-known select box; this would make
  385.  * a quick check possible and would cut down the computation for short
  386.  * mouse movements (the most common).
  387.  */
  388.  
  389. static SHORT pop_computestate (win, menu)
  390. struct Window *win;
  391. struct Menu *menu;
  392.  
  393. {
  394.  
  395.    register SHORT current = 0;
  396.    register SHORT xval, yval;
  397.    register struct MenuItem *item;
  398.  
  399.    /* Get the x and y vals of the mouse position */
  400.  
  401.    xval = win->MouseX;
  402.    yval = win->MouseY;
  403.  
  404.    /* If there is a title, decrement the yval by the correct amount */
  405.  
  406.    if (menu->MenuName)
  407.       yval -= POPTITLEHEIGHT;
  408.  
  409.    /* First, see if the pointer is even in the window */
  410.  
  411.    if ((xval < 0) || (yval < 0) ||
  412.       (xval > win->Width) || (yval > win->Height))
  413.          return (-1);
  414.  
  415.    /* search through the list of menu items, checking the select box  */
  416.    /* of each.  If containment is detected, the job is done.          */
  417.  
  418.    item = menu->FirstItem;
  419.    while (item)  {
  420.       if ((xval >= item->LeftEdge) && (yval >= item->TopEdge) &&
  421.          (xval <= item->LeftEdge + item->Width) &&
  422.          (yval <= item->TopEdge + item->Height))  {
  423.  
  424.          /* We have found the quarry; now, the result only  */
  425.          /* depends on the MenuItem's ITEMENABLED flag.     */
  426.  
  427.          if (item->Flags & ITEMENABLED)
  428.             return (current);
  429.          else
  430.             return (-1);
  431.       }
  432.       current++;
  433.       item = item->NextItem;
  434.    }
  435.  
  436.    /* If the list is exhausted, return the sad news */
  437.  
  438.    return (-1);
  439. }
  440.  
  441. /* ============================================================= */
  442.  
  443. /*
  444.  * pop_highlight()
  445.  *
  446.  * highlight a menu item
  447.  */
  448.  
  449. static VOID pop_highlight (win, menu, state)
  450.  
  451. struct Window *win;
  452. struct Menu *menu;
  453. SHORT state;
  454.  
  455. {
  456.  
  457.    pop_do_highlighting (win, menu, state, 0);
  458.  
  459. }
  460.  
  461. /* ============================================================= */
  462.  
  463. /*
  464.  * pop_unhighlight()
  465.  *
  466.  * unhighlight a menu item
  467.  */
  468.  
  469. static VOID pop_unhighlight (win, menu, state)
  470.  
  471. struct Window *win;
  472. struct Menu *menu;
  473. SHORT state;
  474.  
  475. {
  476.  
  477.    pop_do_highlighting (win, menu, state, 1);
  478.  
  479. }
  480.  
  481. /* ============================================================= */
  482.  
  483. /*
  484.  * pop_do_highlighting()
  485.  *
  486.  * Highlight or unhighlight a menu item, given its traversal number.  Assumes
  487.  * this is a rational value -- if it isn't, Watch Out.
  488.  */
  489.  
  490. static VOID pop_do_highlighting (win, menu, state, mode)
  491.  
  492. struct Window *win;
  493. struct Menu *menu;
  494. SHORT state;
  495. SHORT mode;                            /* 0 means to highlight,  */
  496.                                        /* 1 means to unhighlight */
  497.  
  498. {
  499.  
  500.    register struct MenuItem *item;
  501.    struct RastPort *rp;
  502.    SHORT offset = 0;
  503.  
  504.    if (menu->MenuName)
  505.       offset = POPTITLEHEIGHT;
  506.  
  507.    /* Get the correct MenuItem structure */
  508.  
  509.    item = pop_getitem (menu, state);
  510.  
  511.    rp = win->RPort;
  512.  
  513.    /* Now, do the highlighting!  The action to be taken depends on    */
  514.    /* the type of highlighting desired for this item.                 */
  515.    /* The way that the flags for highlighting works is truly bizarre  */
  516.  
  517.    if ((item->Flags & HIGHNONE) == HIGHNONE)
  518.       return;
  519.  
  520.    if (item->Flags & HIGHCOMP)  {
  521.       SetDrMd (rp, COMPLEMENT);
  522.       RectFill (rp, (LONG) item->LeftEdge, (LONG) (item->TopEdge +
  523.         offset), (LONG) (item->LeftEdge + item->Width - 1),
  524.         (LONG) (item->TopEdge + item->Height + offset));
  525.    }
  526.    else if (item->Flags & HIGHBOX)  {
  527.       SetDrMd (rp, COMPLEMENT);
  528.       Move (rp, (LONG) item->LeftEdge, (LONG) (item->TopEdge + 
  529.         offset));
  530.       Draw (rp, (LONG) (item->LeftEdge + item->Width - 1),
  531.         (LONG) (item->TopEdge + offset));
  532.       Draw (rp, (LONG) (item->LeftEdge + item->Width - 1),
  533.         (LONG) (item->TopEdge + item->Height + offset));
  534.       Draw (rp, (LONG) item->LeftEdge,
  535.         (LONG) (item->TopEdge + item->Height + offset));
  536.       Draw (rp, (LONG) item->LeftEdge, (LONG) 
  537.         (item->TopEdge + offset));
  538.    }
  539.  
  540.    /*  Otherwise, the mode is HIGHIMAGE */
  541.  
  542.    else
  543.       pop_draw_menuitem (win, item, !mode, offset);
  544. }
  545.  
  546. /* ============================================================= */
  547.  
  548. /*
  549.  * pop_render()
  550.  *
  551.  * renders the menu title (if existent) and the menu items
  552.  */
  553.  
  554. static VOID pop_render (win, menu)
  555.  
  556. struct Window *win;
  557. struct Menu *menu;
  558.  
  559. {
  560.  
  561.    struct MenuItem *item;
  562.    struct RastPort *rp;
  563.    SHORT offset = 0;
  564.  
  565.    rp = win->RPort;
  566.  
  567.    /* Fill the background with color 1, like Intuition Menus */
  568.  
  569.    SetAPen (rp, 1L);
  570.    RectFill (rp, 0L, 0L, (LONG) win->Width, (LONG) win->Height);
  571.  
  572.    /* First, if there is a Title for this menu, render it in the top */
  573.    /* of the menu.                                                   */
  574.  
  575.    if (menu->MenuName)  {
  576.       SetDrMd (rp, JAM1);
  577.       SetAPen (rp, 0L);
  578.       SetBPen (rp, 1L);
  579.       Move (rp, 4L, 7L);
  580.       Text (rp, menu->MenuName, (LONG) pop_strlen(menu->MenuName));
  581.       SetDrMd (rp, COMPLEMENT);
  582.       RectFill (rp,0L,0L, (LONG) win->Width, (LONG) POPTITLEHEIGHT);
  583.       SetDrMd (rp, JAM1);
  584.       offset = POPTITLEHEIGHT;
  585.    }
  586.  
  587.    /* now render all of the menu items */
  588.  
  589.    item = menu->FirstItem;
  590.    while (item)  {
  591.       pop_draw_menuitem (win, item, 0, offset);
  592.       item = item->NextItem;
  593.    }
  594. }
  595.  
  596. /* ============================================================= */
  597.  
  598. /* Area fill patterns */
  599.  
  600. static USHORT pop_ghost_pattern[] = {
  601.    0x1111, 0x4444
  602. };
  603. static USHORT pop_normal_pattern[] = {
  604.    0xffff, 0xffff
  605. };
  606.  
  607. /* ============================================================= */
  608.  
  609. /*
  610.  * pop_draw_menuitem()
  611.  *
  612.  * Draws the specified menuitem in the given rastport.  The mode argument
  613.  * says what to draw -- 0 means draw the ItemFill, 1 the SelectFill.
  614.  */
  615.  
  616. static VOID pop_draw_menuitem (win, item, mode, offset)
  617.  
  618. struct Window *win;
  619. struct MenuItem *item;
  620. SHORT mode;
  621. SHORT offset;
  622.  
  623. {
  624.  
  625.    APTR fill;
  626.    struct RastPort *rp;
  627.  
  628.    /* first, figure out what to do, and return if it is a NULL thing */
  629.  
  630.    if (!mode)
  631.       fill = item->ItemFill;
  632.    else
  633.       fill = item->SelectFill;
  634.  
  635.    if (!fill)
  636.       return;
  637.  
  638.    rp = win->RPort;
  639.  
  640.    /* First, erase what may already be there, just to be sure that    */
  641.    /* everything works out all right.                                 */
  642.  
  643.    SetAPen (rp, 1L);
  644.    SetDrMd (rp, JAM1);
  645.    RectFill (rp, (LONG) item->LeftEdge, (LONG) (item->TopEdge +
  646.      offset), (LONG) (item->LeftEdge + item->Width), (LONG)
  647.      (item->TopEdge + item->Height + offset));
  648.  
  649.    /* If the item is checkmarked, draw the checkmark.  Intuition made */
  650.    /* sure that the CheckMark field of the window structure exists    */
  651.  
  652.    if (item->Flags & CHECKIT)
  653.       if (item->Flags & CHECKED)
  654.          DrawImage (rp, win->CheckMark, (LONG)  item->LeftEdge,
  655.            (LONG) (item->TopEdge + offset + 1));
  656.  
  657.    /* Now, draw the item itself -- depending on the Flag value, it    */
  658.    /* could be either an Image or an IntuiText                        */
  659.  
  660.    if (item->Flags & ITEMTEXT)
  661.       PrintIText (rp, fill, (LONG) item->LeftEdge, 
  662.         (LONG) (item->TopEdge + offset));
  663.    else
  664.       DrawImage (rp, fill, (LONG) item->LeftEdge, 
  665.         (LONG) (item->TopEdge + offset));
  666.  
  667.    /* If the ITEMENABLED flag is not set, "ghost" the item.           */
  668.  
  669.    if (!(item->Flags & ITEMENABLED))  {
  670.       SetAPen (rp, 1L);
  671.       SetDrMd (rp, JAM1);
  672.       SetAfPt (rp, (USHORT *) pop_ghost_pattern, 1L);
  673.       RectFill (rp, (LONG) item->LeftEdge, (LONG) (item->TopEdge +
  674.         offset), (LONG) (item->LeftEdge + item->Width), (LONG)
  675.         (item->TopEdge + item->Height + offset));
  676.       SetAfPt (rp, (USHORT *) pop_normal_pattern, 1L);
  677.    }
  678. }
  679.  
  680. /* ============================================================= */
  681.  
  682. /*
  683.  * pop_getitem()
  684.  *
  685.  * given the traversal number of a menu item in a menu (assumes, BTW, that
  686.  * the arguments are valid), return a pointer to the MenuItem structure
  687.  */
  688.  
  689. static struct MenuItem *pop_getitem (menu, which)
  690.  
  691. struct Menu *menu;
  692. SHORT which;
  693.  
  694. {
  695.  
  696.    struct MenuItem *item;
  697.  
  698.    item = menu->FirstItem;
  699.    while (which--)
  700.       item = item->NextItem;
  701.    return (item);
  702. }
  703.  
  704. /* ============================================================= */
  705.  
  706. /*
  707.  * pop_strlen()
  708.  *
  709.  * a home-brewed strlen to prevent it being necessary to hook in whatever
  710.  * huge object file in which the c library's strlen() resides.
  711.  */
  712.  
  713. static SHORT pop_strlen (str)
  714.  
  715. char *str;
  716.  
  717. {
  718.  
  719.    register SHORT count = 0;
  720.  
  721.    for (; *str++; count++);
  722.    return (count);
  723. }
  724.  
  725. /* :-) */
  726.